#include "QueueThread.h"


/////////////////////////////////////////////////////////////////////////////

MQueueThread::MQueueThread()
{
	m_lpThread = NULL;
	m_hEndEvent = NULL;
	m_hQueue = NULL;
	m_dwElaps = INFINITE;
	m_hQueue = CreateEvent(NULL, TRUE, FALSE, NULL);
	m_hEndEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	InitializeCriticalSection(&m_CriticalSection);
}

MQueueThread::~MQueueThread()
{
	if(m_hEndEvent != NULL){
		CloseHandle(m_hEndEvent);
		m_hEndEvent = NULL;
	}
	if(m_hQueue != NULL){
		CloseHandle(m_hQueue);
		m_hQueue = NULL;
	}
	DeleteCriticalSection(&m_CriticalSection);
}

/////////////////////////////////////////////////////////////////////////////

BOOL MQueueThread::StartThread(void *lpParam)
{
	if((m_lpThread != NULL) || (m_hEndEvent == NULL) || (m_hQueue == NULL)) {
		return FALSE;
	}
	m_ThreadInfo.m_lpThread = this;
	m_ThreadInfo.m_lpParam = lpParam;

	m_bThreadExec = TRUE;

	m_lpThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)WorkerThread, &m_ThreadInfo, 0, 0);

	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
void MQueueThread::EndThread()
{
	m_bThreadExec = FALSE;

	if(m_hEndEvent != NULL){
		SetEvent(m_hEndEvent);
		if(m_lpThread != NULL){
			WaitForSingleObject(m_lpThread, INFINITE);
			CloseHandle(m_lpThread);
		}
		CloseHandle(m_hEndEvent);
		m_hEndEvent = NULL;
	}
}

/////////////////////////////////////////////////////////////////////////////
UINT MQueueThread::WorkerThread(void *lpParam)
{
	MQueueThreadInfo *lpThreadInfo = (MQueueThreadInfo*)lpParam;
	return lpThreadInfo->m_lpThread->Run();
}

/////////////////////////////////////////////////////////////////////////////
void MQueueThread::SetTimer(UINT uElapse)
{
	m_dwElaps = uElapse;
}

/////////////////////////////////////////////////////////////////////////////
UINT MQueueThread::Run()
{
	if(!InitThread(m_ThreadInfo.m_lpParam)){
		return 0;
	}
	HANDLE hEvent[2] = {
			m_hEndEvent,
			m_hQueue};
	DWORD dwRet;
	int nRet;
	BOOL bLoop = TRUE;
	while(bLoop){
		dwRet = MsgWaitForMultipleObjects(2, hEvent, FALSE, m_dwElaps, QS_ALLINPUT);
		switch(dwRet){
		case WAIT_OBJECT_0:		// Thread terminate request
			bLoop = FALSE;
			break;
		case WAIT_OBJECT_0+1:	
			{
				MQueueParam *lpQueueParam;
				//while(ThreadQueue(QUEUE_GET, (DWORD)&lpQueueParam)){
				while((nRet=ThreadQueue(QUEUE_GET, (DWORD)&lpQueueParam)) > 0){
					ProcessQueue(lpQueueParam);
					delete lpQueueParam;
					if(CheckEndRequest() == WAIT_OBJECT_0){
						break;
					}
				}
			}
			break;

		case WAIT_OBJECT_0+2:	
			{
				MSG msg;
				while(PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)){
					if(	m_bThreadExec ){
//					if(CheckEndRequest() == WAIT_OBJECT_0){
						::DispatchMessage(&msg);
					}
				}
			}
			break;

		case WAIT_TIMEOUT:		
			{
				ProcessTimeout();
			}
			break;
		}
	}
	ExitThread();
	return 1;
}

/////////////////////////////////////////////////////////////////////////////
BOOL MQueueThread::InitThread(void *lpParam)
{
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
int MQueueThread::ThreadQueue(DWORD dwType, ULONGLONG dwParam1, ULONGLONG dwParam2)
{
	EnterCriticalSection(&m_CriticalSection);
	int nRet = 0;
	switch(dwType){
	case QUEUE_ADD:
		{
			MQueueParam *lpQueueParam = new MQueueParam;
			lpQueueParam->m_dwParam1 = dwParam1;
			lpQueueParam->m_dwParam2 = dwParam2;
			nRet = OnAddQueue(lpQueueParam); // dwRet<0: has processed but occur error; dwRet=0: has processed and sucessed. 
			if(nRet <= 0){
				//dwRet = 0;
				delete lpQueueParam;
			}else{
				nRet = 1;
				//m_Queue.AddTail(lpQueueParam);
				m_Queue.push_back(lpQueueParam);
				SetEvent(m_hQueue);
			}
		}
		break;
	case QUEUE_GET:
		{
			if(m_Queue.size() == 0){
				nRet = 0;
			}else{
				//MQueueParam *lpQueueParam = (MQueueParam*)m_Queue.RemoveHead();
				MQueueParam *lpQueueParam = (MQueueParam*)m_Queue.front();
				m_Queue.pop_front();
				*((LPDWORD)(dwParam1)) = (DWORD)lpQueueParam;
				nRet = 1;
				if(m_Queue.size() == 0){
					ResetEvent(m_hQueue);
				}
			}
		}
		break;
	case QUEUE_COUNT:
		{
			nRet = m_Queue.size();
		}
		break;
	}
	LeaveCriticalSection(&m_CriticalSection);
	return nRet;
}

/////////////////////////////////////////////////////////////////////////////
BOOL MQueueThread::OnAddQueue(MQueueParam *lpQueueParam)
{
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
void MQueueThread::ProcessQueue(MQueueParam *lpQueueParam)
{
}

/////////////////////////////////////////////////////////////////////////////
void MQueueThread::ProcessTimeout()
{
}

/////////////////////////////////////////////////////////////////////////////
DWORD MQueueThread::CheckEndRequest()
{
	return WaitForSingleObject(m_hEndEvent, 0);
}

/////////////////////////////////////////////////////////////////////////////
void MQueueThread::ExitThread()
{
}
